﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SharpShare.Storage.FileSystem {
    public class TrackingFileStorageItemFactory : IFileStorageItemFactory {
        private FileStorageOptions _options;
        private object _lock = new object();
        private Dictionary<string, WeakReference> _items = new Dictionary<string, WeakReference>(new PathComparer());

        public TrackingFileStorageItemFactory(FileStorageOptions options = null) {
            if (options == null) {
                options = new FileStorageOptions();
            }

            _options = options.Clone();
        }

        #region IFileStorageItemFactory Members

        public FileStorageOptions Options {
            get {
                return _options.Clone();
            }
        }

        public FileStorageItem Create(string path) {
            lock (_lock) {
                FileStorageItem item = null;

                if (_items.ContainsKey(path)) {
                    item = (_items[path].Target as FileStorageItem);
                    if (item != null && !item.Exists) {
                        item = null;
                    }
                    if (item == null) {
                        _items.Remove(path);
                    }
                }

                if (item == null) {
                    item = FileStorageItem.Create(path, this);
                    if (item != null && item.Exists) {
                        _items[path] = new WeakReference(item);
                    }
                }

                return item;
            }
        }

        public void Relocate(string oldPath, string newPath) {
            lock (_lock) {
                if (_items.ContainsKey(oldPath)) {
                    FileStorageItem oldItem = (_items[oldPath].Target as FileStorageItem);

                    _items.Remove(oldPath);

                    if (oldItem != null) {
                        if (!PathUtils.IsEqual(oldItem.Info.FullName, newPath)) {
                            oldItem.Relocate(newPath);
                        }

                        _items[newPath] = new WeakReference(oldItem);
                    }
                }

                var childKeys = _items.Keys
                    .Where(i => PathUtils.IsChild(oldPath, i))
                    .ToList();

                foreach (string path in childKeys) {
                    FileStorageItem item = (_items[path].Target as FileStorageItem);
                    if (item == null) {
                        _items.Remove(path);
                        continue;
                    }

                    string relative = PathUtils.MakeRelative(oldPath, path);
                    string newChildPath = PathUtils.Combine(newPath, relative);

                    item.Relocate(newChildPath);

                    _items.Remove(path);
                    _items[newChildPath] = new WeakReference(item);

                    Relocate(path, newChildPath);
                }
            }
        }

        #endregion
    }
}
